#include "ME.h"


ME::ME(int columnSize, int width, int height, int meRange)
{
	_columnSize = columnSize;
	_width = width;
	_height = height;
	_meRange = meRange;
}


ME::~ME(void)
{
}

MADInfoContainer ME::calculateMotionVector(Matrix& targetBlock, int tbX, int tbY, BlockList& previousFrame)
{
	int type = 2;

	int centerX = tbX;
	int centerY = tbY;
	int lowX = tbX-_meRange;
	if(lowX < 0)
		lowX = 0;
	int lowY = tbY-_meRange;
	if(lowY < 0)
		lowY = 0;
	int highX = tbX+_meRange;
	int highY = tbY+_meRange;

	int limX = std::min(highX, _width-_columnSize);
	int limY = std::min(highY, _height-_columnSize);

	int columns = limX - lowX + 1;
	int rows = limY - lowY + 1;
	int size = rows*columns;

	MADInfoContainer* MADArray = new MADInfoContainer[size];

#if P_ENC_ME == 1
#pragma omp parallel for
#endif
	for(int k = 0; k < size; ++k)
	{
		int blockCol = k % columns + lowX;
		int blockRow = k / columns + lowY;

		Matrix comparingBlock = previousFrame.getBlockAtCoord(blockCol, blockRow);

		MADInfoContainer& MIC = MADArray[k];

		MIC.diff  = targetBlock - comparingBlock;

		double currentMAD = calculateMAD(MIC.diff);

		MIC.MAD = currentMAD;

		MIC.comparingBlock = comparingBlock;
		MIC.x = blockCol-centerX;
		MIC.y = blockRow-centerY;
	}

	MADInfoContainer returnValue;

	returnValue.MAD = INT_MAX;

	for(int i = 0; i < size; ++i)
	{
		if(MADArray[i].MAD < returnValue.MAD)
		{
			returnValue = MADArray[i];
		}
	}

	delete[] MADArray;

	if(returnValue.MAD == 0)
		type = 0;

	returnValue.type = type;

	return returnValue;

}

Matrix* ME::calculateDifference(Matrix *target, Matrix *reference)
{
	Matrix *diff = new Matrix(_columnSize);

	*diff = (*target) - (*reference);

	return diff;
}

double ME::calculateMAD(Matrix& matrix)
{
	int madTot = 0;

	for(int i = 0; i < _columnSize*_columnSize; ++i)
	{
		int val = matrix[i];
		if(val < 0)
			val = -val;

		madTot += val;

	}

	return (double)madTot/256.0;
}
